package com.keya.device;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.keya.base.exception.BusinessException;
import com.keya.features.gateway.Gateway;
import com.keya.features.tool.DicomNetParams;
import com.keya.features.tool.EchoSCU;
import com.keya.mapper.DeviceMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Set;

@Service
public class DeviceService extends ServiceImpl<DeviceMapper, Device> {


    @Resource
    DeviceMapper deviceMapper;
    @Resource
    DeviceProperties deviceProperties;
    @Resource
    GatewayProperties gatewayProperties;
    @Resource
    Gateway gateWay;

    @Transactional
    public Device getLocalHost() throws Exception {
        QueryWrapper<Device> query = new QueryWrapper<Device>()
                .isNull("type")
                .last(String.format("limit %d", 1));
        List<Device> devices = deviceMapper.selectList(query);
        Device device = devices.size() == 1 ? devices.get(0) : null;
        if (device == null) {
            device = new Device();
            device.setCreatedAt(new Date());
            device.setUpdatedAt(new Date());
            device.setId(null);
            device.setIp(gatewayProperties.getServerAddr());
            device.setPort(gatewayProperties.getServerPort().toString());
            device.setAetitle(gatewayProperties.getAetitle());
            device.setCreatedAt(new Date());
            device.setUpdatedAt(new Date());
            // FIXME: error check
            if (deviceMapper.insert(device) != 1) {
                throw new Exception("failed to insert localhost device");
            }
        }
        if (!device.getIp().equals(gatewayProperties.getServerAddr()) || !device.getPort().equals(gatewayProperties.getServerPort().toString())) {
            device.setIp(gatewayProperties.getServerAddr());
            device.setPort(gatewayProperties.getServerPort().toString());
            deviceMapper.updateById(device);
        }
        return device;
    }

    public Device updateLocalHost(String aet, String name) throws Exception {
        Device device = getLocalHost();
        device.setAetitle(aet);
        device.setIp(gatewayProperties.getServerAddr());
        device.setName(name);
        device.setPort(gatewayProperties.getServerPort().toString());
        device.setUpdatedAt(new Date());
        deviceMapper.updateById(device);
        gateWay.setAETitle(aet);
        return device;
    }

    public Device getDeviceById(int id) {
        return deviceMapper.selectById(id);
    }


    @Transactional
    public Device update(Device device) {
        if (ObjectUtil.isEmpty(device.getId())) {
            throw new BusinessException(-1, "id 不能为空");
        }
        if (device.getType() == null) {
            throw new BusinessException(-1, "unsupported device type");
        }
        List<Device> devices = deviceMapper.selectList(
                new LambdaQueryWrapper<Device>()
                        .eq(Device::getAetitle, device.getAetitle())
                        .eq(Device::getIp, device.getIp())
                        .ne(Device::getId, device.getId()));
        if (devices.size() > 0) {
            throw new BusinessException(-1, "aetitle、ip必须唯一");
        }
        devices = deviceMapper.selectList(
                new LambdaQueryWrapper<Device>().eq(Device::getName, device.getName()).ne(Device::getId, device.getId()));
        if (devices.size() > 0) {
            throw new BusinessException(-1, "设备名称必须唯一");
        }
        device.setUpdatedAt(new Date());
        updateById(device);
        return device;
    }

    public Device insert(Device device) throws Exception {
        if (device.getType() == null) {
            throw new Exception("unsupported device type");
        }
        List<Device> devices = deviceMapper.selectList(
                new LambdaQueryWrapper<Device>()
                        .eq(Device::getAetitle, device.getAetitle())
                        .eq(Device::getIp, device.getIp()));
        if (devices.size() > 0) {
            throw new Exception("aetitle、ip必须唯一");
        }
        devices = deviceMapper.selectList(
                new LambdaQueryWrapper<Device>().eq(Device::getName, device.getName()));
        if (devices.size() > 0) {
            throw new Exception("设备名称必须唯一");
        }
        device.setUpdatedAt(new Date());
        device.setCreatedAt(new Date());
        deviceMapper.insert(device);
        return device;
    }

    public List<Device> getByAetitle(String aetitle) {
        LambdaQueryWrapper<Device> lambdaQueryWrapper = new LambdaQueryWrapper<Device>();
        lambdaQueryWrapper.eq(Device::getAetitle, aetitle);
        return deviceMapper.selectList(lambdaQueryWrapper);
    }

    public List<Device> listDevices() {
        LambdaQueryWrapper<Device> lambdaQueryWrapper = new LambdaQueryWrapper<Device>();
        lambdaQueryWrapper.isNotNull(Device::getType);
        lambdaQueryWrapper.orderByAsc(Device::getId);
        return deviceMapper.selectList(lambdaQueryWrapper);
    }

    public int typeNotNullCount() {
        LambdaQueryWrapper<Device> lambdaQueryWrapper = new LambdaQueryWrapper<Device>();
        lambdaQueryWrapper.isNotNull(Device::getType);
        Long aLong = deviceMapper.selectCount(lambdaQueryWrapper);
        if (aLong != null) {
            return aLong.intValue();
        }
        return 0;
    }

    @Transactional(rollbackFor = Exception.class)
    public void deleteByAetitle(Integer id) {
        Device device = getById(id);
        removeById(device);
    }

    public String testByAetitle(Integer id) throws Exception {
        Device device = getById(id);
        if (device == null) {
            return "no aetitle";
        }
        int status = new EchoSCU().cEcho(new DicomNetParams(
                device.getAetitle(), device.getIp(), device.getPort(),
                getLocalHost().getAetitle(), deviceProperties.getPingTimeout()));
        return status == 0 ? null : "ping failed";
    }

    public List<Device> listByType(String type) {
        return list(new LambdaQueryWrapper<Device>().orderByAsc(Device::getId).eq(Device::getType, type));
    }
}
